#pragma once
#include <iostream>
#include <memory>
#include <unordered_map>
#include "Epoller.hpp"
#include "Event.hpp"

class Reactor{
private:
    bool IsConnectionExistsHelper(int sockfd)
    {
        auto n = _connections.find(sockfd);
        if(n == _connections.end())
        {
            return false;
        }
        return true;
    }


    bool IsConnectionExists(std::shared_ptr<Connection>& conn)
    {
        return IsConnectionExistsHelper(conn->GetFd());
    }


    bool IsConnectionExists(int sockfd)
    {
        return IsConnectionExistsHelper(sockfd);
    }


    bool IsConnectionEmpty()
    {
        return _connections.empty();
    }

    int LoopOnce()
    {
        
        return _epoller_ptr -> WaitEvents(_event_space->GetEventSpace(), _event_space->GetEventSize());
    }
    

    void Dispatcher(int n)
    {
                    
        //遍历就绪的文件描述符
        for(int i = 0; i < n; i++)
        {
            //获得就绪的文件描述符
            int sockfd = _event_space->GetReadFd(i);
            //获得对应就绪文件描述符的事件
            int event = _event_space->GetReadEvent(i);

            //两个if将所有的异常处理转换成I/O错误
            if(event & EPOLLERR)
            {
                //监听文件描述符时发生错误
                event |= (EPOLLIN | EPOLLOUT);
            }
            if(event & EPOLLHUP)
            {
                //对端关闭链接
                event |= (EPOLLIN | EPOLLOUT);
            }

            //处理读事件就绪
            if(event & EPOLLIN)
            {
                if(IsConnectionExists(sockfd))
                {
                    _connections[sockfd]->Recver();
                }
            }
            
            //写事件处理
            if(event & EPOLLOUT)
            {
                if(IsConnectionExists(sockfd))
                {
                    _connections[sockfd]->Sender();
                }
            }
        }
        
    }
public:
    Reactor()
    :_epoller_ptr(std::make_unique<Epoller>()),
     _event_space(std::make_shared<Event>()),
     _isruning(false)
    {

    }

    void Loop()
    {
        if(IsConnectionEmpty())
            return;
        _isruning = true;
        while(_isruning)
        {
            Print();
            int n = LoopOnce();
            Dispatcher(n);
        

        }
        _isruning = false;
    }
    void AddConnection(std::shared_ptr<Connection>& conn)
    {
        //要添加的文件描述符必须存在
        if(IsConnectionExists(conn))
        {
            return;
        }
        //要获取事件和文件描述符
        int fd = conn->GetFd();
        int event = conn->GetEvent();

        //设置回指指针
        conn->SetOwner(this);

        //让服务器将不同的链接管理起来，通过fd查找
        _connections[fd] = conn;

        //将关心的文件描述符和时间设置进内核
        _epoller_ptr->EpllAddEvent(fd, event);

    }

    void EnableReadWrite(int sockfd, bool enableread, bool enablewrite)
    {
        if(!IsConnectionExists(sockfd))
        {
            //没有该文件描述符
            LOG(LogLevel::ERROR) << "EnableReadWrite error";
            return;
        }

        //修改sockfd的关心事件
        uint32_t new_event = (EPOLLET | (enableread ? EPOLLIN : 0) | (enablewrite ? EPOLLOUT : 0));
        _connections[sockfd]->SetEvent(new_event);

        //将新事件设置到内核
        _epoller_ptr->EpollModEvent(new_event, new_event);
    }

    void DelConnection(int sockfd)
    {
        //先从自己的内核中进行移出
        _epoller_ptr->EpollDelEvent(sockfd);

        //清除连接关系
        _connections.erase(sockfd);

        //关闭文件描述符
        close(sockfd);

        LOG(LogLevel::FATAL) << "一个文件描述符退出: " << sockfd;


    }

    void Print()
    {
        std::cout << "当前Reactor正在管理的fd: ";
        for(auto& conn : _connections)
        {
            std::cout << conn.second->GetFd() << " ";
        }
        std::cout << std::endl;
    }
    void stop()
    {
        _isruning = false;
    }
    ~Reactor(){}
private:
    bool _isruning;
    //管理epoll模型
    std::unique_ptr<Epoller> _epoller_ptr;
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;
    //就绪文件描述符管理空间
    std::shared_ptr<Event> _event_space;
};